﻿
using System;
using System.Globalization;
using System.Text.RegularExpressions;

namespace NoNameGoServer.Client.Commands {
    public class StatsCommand : Command {
        private readonly string _playerName;
        private readonly CompletedArgs _completedArgs = new CompletedArgs();

		public CompletedArgs Results { get { return _completedArgs; } }

        /// <summary>
        /// Gets stats for current player
        /// </summary>
        public StatsCommand()
            : this(null) {
        }

        public StatsCommand(string playerName) {
            _playerName = playerName;
        }

        public override void Execute(NNGSClient nngsClient) {
            string cmd = _playerName == null ? string.Format("stats\n") : string.Format("stats {0}\n", _playerName);
            nngsClient.SendAsync(this, cmd, null);
        }

        public override void ProcessReceivedLine(NNGSClient nngsClient, string line, out bool processed) {
            if (line == "1 5") {
                FireCompleted(this, _completedArgs);
                processed = true;
            } else if (line.StartsWith("9 ")) {
                line = line.Substring("9 ".Length);
                int fieldSeperator = line.IndexOf(':');
                if (fieldSeperator > 0) {
                    string fieldName = line.Substring(0, fieldSeperator).Trim().ToLowerInvariant();
                    string value = line.Substring(fieldSeperator + 1).Trim();
                    ProcessFieldLine(fieldName, value);
                } else {
                    ProcessOtherLine(line);
                }
                processed = false;
            } else {
                processed = false;
            }
        }

        private void ProcessFieldLine(string fieldName, string value) {
            switch (fieldName) {
                case "player":
                    _completedArgs.Player = value;
                    break;
                case "game":
                    _completedArgs.Game = value;
                    break;
                case "language":
                    _completedArgs.Language = value;
                    break;
                case "rating":
                    ParseRating(value);
                    break;
                case "rated games":
                    _completedArgs.RatedGames = ParseIntValue(value);
                    break;
                case "rank":
                    _completedArgs.RankSetByPlayer = value;
                    break;
                case "wins":
                    _completedArgs.Wins = ParseIntValue(value);
                    break;
                case "losses":
                    _completedArgs.Losses = ParseIntValue(value);
                    break;
                case "idle time":
                    _completedArgs.IdleTime = ParseTimeSpan(value);
                    break;
                case "address":
                    _completedArgs.Address = value;
                    break;
                case "country":
                    _completedArgs.Country = value;
                    break;
                case "reg date":
                    _completedArgs.RegDate = ParseDateTime(value);
                    break;
                case "info":
                    _completedArgs.Info = value;
                    break;
                case "defaults (help defs)":
                    ProcessDefaultsValue(value);
                    break;
            }
        }

        private void ParseRating(string value) {
            value = Regex.Replace(value, @"\s+", " ").Trim();
            string[] parts = value.Split(' ');
            if (parts[0].EndsWith("*")) {
                _completedArgs.IsRated = true;
                parts[0] = parts[0].Substring(0, parts[0].Length - 1);
            } else {
                _completedArgs.IsRated = false;
            }
            _completedArgs.Rank = parts[0];
            _completedArgs.Rating = parts[1];
        }

        private DateTime ParseDateTime(string value) {
            value = Regex.Replace(value, @"\s+", " ").Trim();
            return DateTime.ParseExact(value, "ddd MMM d HH:mm:ss yyyy", CultureInfo.CurrentCulture);
        }

        private TimeSpan ParseTimeSpan(string value) {
            // TODO: parse this value...   (On server) 0s
            return new TimeSpan(1);
        }

        private int ParseIntValue(string value) {
            return int.Parse(value);
        }

        private void ProcessDefaultsValue(string value) {
            string[] nameValuePairs = value.Split(',');
            foreach (string nameValuePair in nameValuePairs) {
                ProcessDefaultsValueNameValuePair(nameValuePair.Trim());
            }
        }

        private void ProcessDefaultsValueNameValuePair(string nameValuePair) {
            if (nameValuePair.StartsWith("time", true, CultureInfo.CurrentCulture)) {
                string value = nameValuePair.Substring("time".Length).Trim();
                _completedArgs.Time = int.Parse(value);
            } else if (nameValuePair.StartsWith("size", true, CultureInfo.CurrentCulture)) {
                string value = nameValuePair.Substring("size".Length).Trim();
                _completedArgs.Size = int.Parse(value);
            } else if (nameValuePair.StartsWith("byo-yomi time", true, CultureInfo.CurrentCulture)) {
                string value = nameValuePair.Substring("byo-yomi time".Length).Trim();
                _completedArgs.ByoYomiTime = int.Parse(value);
            } else if (nameValuePair.StartsWith("byo-yomi stones", true, CultureInfo.CurrentCulture)) {
                string value = nameValuePair.Substring("byo-yomi stones".Length).Trim();
                _completedArgs.ByoYomiStones = int.Parse(value);
            } else {
                throw new NNGSClientException("Processing defaults value name value pair: " + nameValuePair);
            }
        }

        private void ProcessOtherLine(string line) {
            line = Regex.Replace(line, @"\s+", " ").Trim();
            string[] parts = line.Split(' ');
            if (parts[0] == "Verbose") {
                return;
            }
            _completedArgs.Verbose = ParseOtherLinePart(parts[0]);
            _completedArgs.Bell = ParseOtherLinePart(parts[1]);
            _completedArgs.Quiet = ParseOtherLinePart(parts[2]);
            _completedArgs.Shout = ParseOtherLinePart(parts[3]);
            _completedArgs.Automail = ParseOtherLinePart(parts[4]);
            _completedArgs.Open = ParseOtherLinePart(parts[5]);
            _completedArgs.Looking = ParseOtherLinePart(parts[6]);
            _completedArgs.Client = ParseOtherLinePart(parts[7]);
            _completedArgs.Kibitz = ParseOtherLinePart(parts[8]);
            _completedArgs.Chatter = ParseOtherLinePart(parts[9]);
        }

        private bool ParseOtherLinePart(string otherLinePart) {
            if (string.Equals(otherLinePart, "on", StringComparison.InvariantCultureIgnoreCase)) {
                return true;
            }
            if (otherLinePart.Equals("off", StringComparison.InvariantCultureIgnoreCase)) {
                return false;
            }
            throw new NNGSClientException("Could not parse other line part: " + otherLinePart);
        }

        public new class CompletedArgs : Command.CompletedArgs {
            public string Player { get; set; }
            public string Game { get; set; }
            public string Language { get; set; }
            public string Rating { get; set; }
            public string Rank { get; set; }
            public bool IsRated { get; set; }
            public int RatedGames { get; set; }
            public string RankSetByPlayer { get; set; }
            public int Wins { get; set; }
            public int Losses { get; set; }
            public TimeSpan IdleTime { get; set; }
            public string Address { get; set; }
            public string Country { get; set; }
            public DateTime RegDate { get; set; }
            public string Info { get; set; }
            public int Time { get; set; }
            public int Size { get; set; }
            public int ByoYomiTime { get; set; }
            public int ByoYomiStones { get; set; }
            public bool Verbose { get; set; }
            public bool Bell { get; set; }
            public bool Quiet { get; set; }
            public bool Shout { get; set; }
            public bool Automail { get; set; }
            public bool Open { get; set; }
            public bool Looking { get; set; }
            public bool Client { get; set; }
            public bool Kibitz { get; set; }
            public bool Chatter { get; set; }
        }
    }
}
